package com.bazaarvoice.ostrich.healthcheck; import com.bazaarvoice.ostrich.HealthCheckResult; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; /** * Policy that results in a bounded, exponentially increasing delay between healthchecks. * <p/> * The delay interval is randomized to avoid the "thundering herd" effect when there are many * clients all attempting to retry at the same time. */ public class ExponentialBackoffHealthCheckRetryDelay implements HealthCheckRetryDelay { private final long _baseDelay; private final long _maxDelayMillis; public ExponentialBackoffHealthCheckRetryDelay(long baseDelay, long maxDelay, TimeUnit unit) { checkArgument(baseDelay >= 0); checkArgument(maxDelay >= baseDelay); checkNotNull(unit); _baseDelay = unit.toMillis(baseDelay); _maxDelayMillis = unit.toMillis(maxDelay); } @Override public long getDelay(int numAttempts, HealthCheckResult result) { checkArgument(numAttempts >= 1); checkNotNull(result); // Pick a random number between baseDelay*2^(n-1) and baseDelay*2^n (inclusive), subject // to the upper bound. long rangeMax = Math.min(_baseDelay * (1 << numAttempts), _maxDelayMillis); long rangeMin = rangeMax / 2; return rangeMin + ThreadLocalRandom.current().nextLong(rangeMax - rangeMin + 1); } }